import 'dart:convert';
import 'dart:io';

import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:crclib/catalog.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qr_code_tools/widgets/page_state_table.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path/path.dart';

import '/utils/dialog.dart';

class ScanToFile extends StatefulWidget {
  const ScanToFile({super.key});

  @override
  State<StatefulWidget> createState() => _ScanToFileState();
}

class _ScanToFileState extends State<ScanToFile> {
  List<List<int>> _contents = [];
  List<int> _contentState = [];
  List<BigInt> _checkCode = [];
  BigInt _checkSum = BigInt.zero;
  int _pageCount = 0;
  int _pageScanned = 0;
  String _fileName = "";
  GlobalKey key = GlobalKey(debugLabel: "ScanToFile");

  Future<void> onPressScan() async {
    // 异步扫码
    var options = const ScanOptions(
        android: AndroidOptions(aspectTolerance: 0.5, useAutoFocus: true),
        autoEnableFlash: false,
        strings: {'cancel': '退出', 'flash_on': '开启闪光灯', 'flash_off': '关闭闪光灯'});
    var result = await BarcodeScanner.scan(options: options);
    // 提取结果
    if (result.type == ResultType.Barcode) {
      if (result.format == BarcodeFormat.qr) {
      } else if (result.format == BarcodeFormat.unknown) {
        return showAlertDialogSafely(
            key.currentContext, "二维码格式错误：${result.formatNote}", "扫描文件二维码");
      } else {
        return showAlertDialogSafely(
            key.currentContext, "二维码格式错误：${result.format.name}", "扫描文件二维码");
      }
    } else if (result.type == ResultType.Error) {
      return showAlertDialogSafely(
          key.currentContext, "扫码失败： ${result.rawContent}", "扫描文件二维码");
    } else {
      // Cancelled
      return;
    }
    // 处理文本
    String text = result.rawContent;
    if (text[0] == 'A') {
      decodeContentA(text.substring(1));
    } else {
      return showAlertDialogSafely(key.currentContext, "内容起始标志不正确", "扫描文件二维码");
    }
  }

  void decodeContentA(String result) {
    // 总数|页码|分页CRC[|文件CRC|文件名]|内容
    List<String> patterns = result.split('|');
    if (patterns.length < 4) {
      return showAlertDialogSafely(key.currentContext, "内容格式错误：分页数据区不足4");
    }
    int patternIndex = 0;
    // 文件总页数
    String countStr = patterns[patternIndex++];
    int? count = int.tryParse(countStr, radix: 16);
    if (count == null) {
      return showAlertDialogSafely(
          key.currentContext, "内容格式错误：总分片数无效($countStr)");
    }
    // 当前分页
    String indexStr = patterns[patternIndex++];
    int? index = int.tryParse(indexStr, radix: 16);
    if (index == null) {
      return showAlertDialogSafely(
          key.currentContext, "内容格式错误：分片号无效($indexStr)");
    }
    if (index >= count) {
      return showAlertDialogSafely(
          key.currentContext, "内容格式错误：分片号大于总数($indexStr)");
    }
    if (index == 0) {
      if (patterns.length < 6) {
        return showAlertDialogSafely(
            key.currentContext, "内容格式错误：首页数据区不足6");
      }
    }
    // 初始化容量
    if (_contents.isEmpty) {
      setState(() {
        resetAllData(count);
      });
    }
    if (_pageCount != count) {
      return showAlertDialogSafely(
          key.currentContext, "内容分片数不一致：${_contents.length} -> $count");
    }
    // 当前页CRC32校验码
    String crc = patterns[patternIndex++];
    var crcSum = BigInt.tryParse(crc, radix: 16);
    if (crcSum == null){
      return showAlertDialogSafely(
          key.currentContext, "分页校验码格式不正确：$crc");
    }
    _checkCode[index] = crcSum;
    if (index == 0) {
      // 文件CRC32校验码
      String sum = patterns[patternIndex++];
      if (_checkSum == BigInt.zero){
        var crcSum = BigInt.tryParse(sum, radix: 16);
        if (crcSum == null){
          return showAlertDialogSafely(
              key.currentContext, "文件校验码格式不正确：$sum");
        }
      }
      // 文件名
      String fileName = patterns[patternIndex++];
      _fileName = fileName;
    }
    // 内容
    String content = patterns[patterns.length - 1];
    List<int> bytes = base64.decode(content);
    var crcSum2 = Crc32Xz().convert(bytes).toBigInt();
    if (crcSum != crcSum2){
      setState(() {
        _contentState[index] = 2;
      });
      return showAlertDialogSafely(
          key.currentContext, "分页校验失败：期望：$crcSum，实际：$crcSum2");
    }
    _contents[index] = bytes;
    setState(() {
      _contentState[index] = 1;
    });
  }

  void resetAllData(int count) {
    _fileName = "";
    _pageCount = count;
    _pageScanned = 0;
    _checkSum = BigInt.zero;
    _contents = List<List<int>>.filled(count, [], growable: false);
    _checkCode = List<BigInt>.filled(count, BigInt.zero, growable: false);
    _contentState = List<int>.filled(count, 0, growable: false);
  }

  void onPressReset() {
    setState(() {
      resetAllData(0);
    });
  }

  void onPressSave() async {
    // 检查数据
    if (_contentState.isEmpty) {
      return showAlertDialogSafely(key.currentContext, '请先扫描文件二维码', '保存文件');
    }
    for (int s in _contentState) {
      if (s != 1) {
        return showAlertDialogSafely(
            key.currentContext, '文件状态未全部就绪，无法保存', '保存文件');
      }
    }
    // 检查权限
    final status = await Permission.storage.request();
    if (status != PermissionStatus.granted) {
      return showAlertDialogSafely(
          key.currentContext, '需要获取存储权限才能保存文件（$status）', '保存文件');
    }
    // 获取存储目录
    Directory? directory;
    try {
      directory ??= await getApplicationDocumentsDirectory();
    } on Exception catch (_, ex) {
      return showAlertDialogSafely(key.currentContext, ex.toString(), "保存文件");
    }
    if (Platform.isAndroid) {
      try {
        directory = await getExternalStorageDirectory();
      } on Exception catch (_) {}
      try {
        directory ??= await getDownloadsDirectory();
      } on Exception catch (_) {}
      try {
        directory ??= await getApplicationDocumentsDirectory();
      } on Exception catch (_, ex) {
        return showAlertDialogSafely(key.currentContext, ex.toString(), "保存文件");
      }
      // 计算外层目录
      int androidIdx = directory.path.indexOf("Android");
      String path = androidIdx > 0
          ? directory.path.substring(0, androidIdx)
          : directory.path;
      directory = Directory(join(path, 'Download/QrCodeTools'));
    }
    directory.createSync(recursive: true);
    File file = File(join(
        directory.path,
        _fileName.isEmpty
            ? 'temp-${DateTime.now().microsecondsSinceEpoch}.txt'
            : _fileName));
    // 写数据
    RandomAccessFile stream = file.openSync(mode: FileMode.writeOnly);
    for (List<int> c in _contents) {
      stream.writeFromSync(c);
    }
    stream.closeSync();
    showAlertDialogSafely(key.currentContext, file.path, "保存文件");
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      key: key,
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        Container(
            margin: const EdgeInsets.only(top: 20),
            child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Text("文件[$_fileName]：$_pageScanned/$_pageCount"),
                ])),
        Expanded(child: PageStateTable(state: _contentState)),
        Container(
            margin: const EdgeInsets.only(left: 10, right: 10, bottom: 20),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                TextButton.icon(
                  icon: const Icon(Icons.save),
                  label: const Text("保存"),
                  onPressed: () => onPressSave(),
                ),
                TextButton.icon(
                  icon: const Icon(Icons.qr_code_scanner),
                  label: const Text("扫一扫"),
                  onPressed: () => onPressScan(),
                ),
                TextButton.icon(
                  icon: const Icon(Icons.clear),
                  label: const Text("重置"),
                  onPressed: () => onPressReset(),
                ),
              ],
            )),
      ],
    );
  }
}
